package database;

import sharedspace.*;

import java.io.IOException;
import java.sql.Timestamp;
import java.text.*;
import java.util.*;

import ocsf.server.ConnectionToClient;
import messages.Message;
import messages.MessageExtraTimeCheck;
import messages.MessageExtraTimeCheckReply;
import messages.Message.MessageType;
import messages.MessageExecuteExamCheckCode.*;
import messages.MessageExecuteExamCodeCheckReply.*;
/**
 * class control for student that make test
 * @author Amir
 *
 */
public class ExecuteExamByStudent {
	
	private Student student;
	private String examCode;
	private String executeTestID;
	private ErrMsg errMsg;
	private ExecuteTest executeTest;
	private StudentInTest studentInTest;
	private List<Choices> choicesList;
	private String endTime;
	private String studentID;
	private String teacherID;
	
	
	
	
 	public ExecuteExamByStudent(){
		
	}
	
	public ExecuteExamByStudent(Student student, String examCode){
		this.student = student;
		this.examCode = examCode; 
	}
	
	public ExecuteExamByStudent(ExecuteTest executeTest)
	{
		this.executeTest = executeTest;
	}
	
	public ExecuteExamByStudent(StudentInTest studentInTest,ExecuteTest executeTest){
		this.studentInTest = studentInTest;
		this.executeTest = executeTest;
		
	}
	
	public ExecuteExamByStudent(String executeTestID,String studentID)
	{
		this.executeTestID = executeTestID;
		this.studentID = studentID;
	}
	
	public ExecuteExamByStudent(String teacherID,List<Choices> choicesList, String endTime)
	{
		this.choicesList = choicesList;
		this.endTime = endTime;
		this.teacherID = teacherID;
	}
	
	/**
	 * check if student inserted a correct code
	 * and refer student to the right test (manual or computerized)
	 * @throws ParseException 
	 */
 	public void checkCodeTest() 
	{
		List<ExecuteTest> exlist;
		// TODO: instead of semester 1 need to define current semester
		try{
		exlist = (new ExecuteTestControl()).getExecuteTestListByCode(examCode, DateUtils.currentYear(), DateUtils.currentSemester());
		for(int i = 0; i<exlist.size(); i++)//check code in executeTest List
		if (exlist.get(i).getTestCode().equals(examCode) && (exlist.get(i).getTestStatus()== true))
			{ 	//code exist in one of the tests
				Course course=(new CourseControl()).getCourseByTestID(exlist.get(i).getTest().getTestID());
				List<Student> slist=(new StudentControl().getStudentListByCourseID(course.getCourseID(), DateUtils.currentYear(), DateUtils.currentSemester()));
				for(int j = 0; j<slist.size(); j++)//check if student is register to the course of the test in current semester
				{
					
					int count = JDBC.countStatment("SELECT count(*) FROM studentintest sit " +
									   "WHERE sit.studentID='"+slist.get(j).getUserID()+"' AND sit.executeTestID='"+exlist.get(i).getExecuteTestID()+"';");
					
					if (slist.get(j).getUserID().equals(student.getUserID()) && count == 0)
						{//student is register to course in current semester
							String now = DateUtils.now(DateUtils.dateFormat);
							SimpleDateFormat dateFormat = new SimpleDateFormat(DateUtils.dateFormat);
							Date date;
							date = dateFormat.parse(now);
							Timestamp nowTime = new Timestamp(date.getTime());
							Executetestinfo executetestinfo = (new ExecuteTestControl()).getExecutetestinfo(exlist.get(i).getExecuteTestID());
							Timestamp startTime = executetestinfo.getStartTime();
							if (nowTime.after(startTime))
						   		{//test started, student can answer the test
									if (exlist.get(i).getTestType().equals("computerized"))
										this.errMsg = ErrMsg.CODE_CORRECT_COMP;
									else if (exlist.get(i).getTestType().equals("manual"))
										this.errMsg = ErrMsg.CODE_CORRECT_WORD;
									this.executeTest = exlist.get(i); 
									return;
								}
						}
				
				}	
				
			}
		this.errMsg = ErrMsg.CODE_INCORRECT;
		}
		catch(ParseException e)
		{
			e.printStackTrace();
		}
		
	}
	/**
	 * get question of test
	 * @return
	 */
	public List<QuestionInTest> getExam()
	{
		List<QuestionInTest> questionInTestList;
		questionInTestList = (new QuestionControl()).getQuestionListByTestID(executeTest.getTest().getTestID());
		return questionInTestList;
			
	}
	/**
	 * update student quantity that start test
	 */
	public void updateStudentStart()
	{
		
		
		JDBC.insertStatment("INSERT into studentintest (executeTestID, studentID,studentComputerGrade,startTest,endTest,testCheckedComplete,wordTestPath) "+
							"values ('"+studentInTest.getExecuteTestID()+"','"+studentInTest.getStudent().getUserID()+
							"',"+studentInTest.getStudentComputerGrade()+",'"+studentInTest.getStartTest()+"','"+studentInTest.getEndTest()+"',"
							+studentInTest.getTestCheckedComplete()+","+studentInTest.getWordTestCheckedPath()+");");
		Executetestinfo executeTestInfo = (new ExecuteTestControl()).getExecutetestinfo(this.executeTest.getExecuteTestID());
		
		JDBC.updateStatment("executetestinfo", "numberStudentStart", "numberStudentStart+1", "executeTestID", executeTestInfo.getExecuteTestID());
	}
	/**
	 * start clock to measur time for student
	 */
	public void startClock()
	{
		
		Timer timer = new Timer();
		
		/**
		 * timerTask - each minute( now second - will change later) server check for extra time
		 *  in ExecuteTestInfo table in database
		 */
		TimerTask timerTask = new TimerTask() {
			
		int extraTime = 0;
		
			@Override
			public void run() {
				// TODO Auto-generated method stub
				try
				{
					//System.out.println(DateUtils.now("HH:mm:ss"));
				    Executetestinfo executeTestinfo = (new ExecuteTestControl()).getExecutetestinfo(executeTestID);
				    /*-----------------------taking-the-current-time-stamp---------------------------------------*/
				    long duration = (new ExecuteTestControl()).getExecuteTestByExecuteTestID(executeTestID).getTest().getTestDuration()*60*1000;
				    String now = DateUtils.now(DateUtils.dateFormat);
					SimpleDateFormat dateFormat = new SimpleDateFormat(DateUtils.dateFormat);
					Date date = dateFormat.parse(now);
					Timestamp nowTime = new Timestamp(date.getTime());
					/*-----------------------calculating-the-final-hour-of-the-test-----------------------------*/
					Timestamp startTime = executeTestinfo.getStartTime();
					long t = startTime.getTime();
					/*add extra time // if extraTime = 0, 0 minutes will be add to final hour*/
					long m = (long)extraTime*60*1000;
					Timestamp endTime = new Timestamp(t+m+duration);
					
					if(nowTime.before(endTime))
						{	/*-----------------------test-is-not-over-yet---------------------------------------*/
							
						    studentInTest = (new StudentControl()).getStudentInTestByExecuteTestID(executeTestID, studentID);
							if (extraTime == 0 )
									{   /*---------------check-for-extra-time-----------------------------------*/
										extraTime = (new ExecuteTestControl()).getExecutetestinfo(executeTestID).getExtraTime();
										//duration+= extraTime*60;
										//System.out.println("add time");
									}
							if (studentInTest.getEndTest().after(studentInTest.getStartTest()))
							{	/*--------------student-submit-the-test,-server-stop-timer-for-student----------*/
								//System.out.println("stop");
								this.cancel();
							}
							boolean b = (new ExecuteTestControl()).getExecuteTestByExecuteTestID(executeTestID).getTestStatus();
							if (b==false)
							{	/*--------test-lock-by-teacher,server-save-time-for-submit-time-of-student------*/
								//System.out.println("stop");
								now = DateUtils.now("yyyy-MM-dd HH:mm:ss");
								JDBC.updateStatmentCloumn("studentintest sit", "endTest", "'"+now+"'", "sit.executeTestID='"+executeTestID+"' AND sit.studentID='"+studentID+"'");
								this.cancel();
							}
							
							
						}
					
					else 
						{	/*--------final-hour-of-test-have-come,test-will-be-lock-for-every-student--------*/
							//System.out.println("time is over");
							// TODO close the test automatic and get student choices for examination
							
							now = DateUtils.now("yyyy-MM-dd HH:mm:ss");
							
							JDBC.updateStatmentCloumn("studentintest sit", "endTest", "'"+now+"'", "sit.executeTestID='"+executeTestID+"' AND sit.studentID='"+studentID+"'");
							JDBC.updateStatmentCloumn("executetest e", "e.testStatue", "false", "e.executeTestID='"+executeTestID+"'");
							this.cancel();
						}
				}
				catch (ParseException e)
				{
					e.printStackTrace();
				}
				
				
				
			}
		};
		
		
		//start timer
		//System.out.println(DateUtils.now("HH:mm:ss"));
		timer.schedule(timerTask, 0, 60*1000);
	}
	
	/**
	 * save answer of computerized test
	 */
	public void setAnswers()
	{
		
		String studentID = choicesList.get(0).getStudentID();
		String executeTestID = choicesList.get(0).getExecuteTestID();
		if (!endTime.equals("")) 
			/*if student submitted the test , the time of submit will be save in database*/
			JDBC.updateStatmentCloumn("studentintest sit", "endTest", "'"+endTime+"'", "sit.executeTestID='"+executeTestID+"' AND sit.studentID='"+studentID+"'");
		
		if(JDBC.countStatment("SELECT count(*) FROM choices c WHERE c.executeTestID='"+ choicesList.get(0).getExecuteTestID()+"' AND c.studentID='"+choicesList.get(0).getStudentID()+"';")==0)
		{	/*save student answers, the system check if the ansers were send by cause of automatic lock or teacher lock */
			for (int i = 0; i<choicesList.size(); i++)
			{
				String questionID = choicesList.get(i).getQuestion().getQuestionID();
				int choice = choicesList.get(i).getChoice();
				JDBC.insertStatment("INSERT into choices (executeTestID,studentID,questionID,choice) " +
									"values ('"+executeTestID+"','"+studentID+"','"+questionID+"',"+choice+");" );
			}	
			
		int grade = checkComputerExam();
		updateStudentFinish();
	
		}
	}
	/**
	 * check test
	 * @return
	 */
	public int checkComputerExam()
	{
		int grade = 0;
		executeTest = (new ExecuteTestControl()).getExecuteTestByExecuteTestID(choicesList.get(0).getExecuteTestID());
		List<QuestionInTest> questionInTestList = (new QuestionControl()).getQuestionListByTestID(executeTest.getTest().getTestID());
		for (int i = 0; i<choicesList.size(); i++)
		{
			if (questionInTestList.get(i).getQuestion().getCorrectAnswer() == choicesList.get(i).getChoice())
				grade+=questionInTestList.get(i).getPointQuestion();
		}
		JDBC.updateStatmentCloumn("studentintest sit", "studentComputerGrade", ""+grade, "sit.executeTestID='"+executeTest.getExecuteTestID()+"' AND sit.studentID='"+choicesList.get(0).getStudentID()+"'");
		JDBC.insertStatment("INSERT into aprovinggrade (teacherID,executeTestID,studentID,studentFianlGrade) " +
				"values ('"+teacherID+"','"+choicesList.get(0).getExecuteTestID()+"','"+choicesList.get(0).getStudentID()+"',"+grade+");");
		System.out.println("your grade is "+grade);
		return grade;
	}
	/**
	 * update student quantity that finish the test
	 */
	public void updateStudentFinish()
	{
		if (!endTime.equals(""))
			{
				JDBC.updateStatment("executetestinfo", "numberStudentFinish", "numberStudentFinish+1", "executeTestID",choicesList.get(0).getExecuteTestID());
				ExecuteTestControl eCtrl = new ExecuteTestControl();
				Executetestinfo executetestinfo = eCtrl.getExecutetestinfo(executeTest.getExecuteTestID());
				//if (executetestinfo.getNumberStudentStart()==executetestinfo.getNumberStudentFinish())
					/*if all student that start test submitted the test then the test will be lock automatic*/
					//JDBC.updateStatmentCloumn("executetest e", "e.testStatue", "false", "e.executeTestID='"+executeTest.getExecuteTestID()+"'");
			}
			
		
	}
	public void saveManualTest(String path)
	{
		String endTime = DateUtils.now(DateUtils.dateFormat);
		JDBC.updateStatmentCloumn("executetestinfo e", "e.numberStudentFinish", "e.numberStudentFinish+1", "executeTestID='"+executeTestID+"'");
		JDBC.updateStatmentCloumn("studentintest sit", "sit.endTest", "'"+endTime+"'", "sit.executeTestID='"+executeTestID+"' AND sit.studentID='"+studentID+"'");
		JDBC.updateStatmentCloumn("studentintest sit", "sit.wordTestPath", "'"+path+"'", "sit.executeTestID='"+executeTestID+"' AND sit.studentID='"+studentID+"'");
		String teacherID = (new ExecuteTestControl()).getExecuteTestByExecuteTestID(executeTestID).getExecuter().getUserID();
		JDBC.insertStatment("INSERT into aprovinggrade(teacherID,executeTestID,studentID) "+
							"values('"+teacherID+"','"+executeTestID+"','"+studentID+"');");
		
	}
	
	public MessageExtraTimeCheckReply checkExtraTime(MessageExtraTimeCheck MsgEtc)
	{
		ExecuteTestControl eCtrl = new ExecuteTestControl();
		ExecuteTest executeTest = eCtrl.getExecuteTestByExecuteTestID(MsgEtc.getExcuteTestID());
		Executetestinfo executetestinfo = eCtrl.getExecutetestinfo(executeTest.getExecuteTestID());
		
		MessageExtraTimeCheckReply reply;
		StudentControl sCtrl = new StudentControl();
		StudentInTest studentInTest = sCtrl.getStudentInTestByExecuteTestID(MsgEtc.getExcuteTestID(), MsgEtc.getStudentID());
		
		if (studentInTest.getEndTest().after(studentInTest.getStartTest()))
			reply = new MessageExtraTimeCheckReply(messages.MessageExtraTimeCheckReply.ErrMsg.TIME_OVER);
		
			else if (executeTest.getTestStatus()==false)
				reply = new MessageExtraTimeCheckReply(messages.MessageExtraTimeCheckReply.ErrMsg.STOP_BY_TEACHER);
		
				else if (executetestinfo.getExtraTime()!=0)
					reply = new MessageExtraTimeCheckReply(executetestinfo.getExtraTime(),messages.MessageExtraTimeCheckReply.ErrMsg.ADD_EXTRA_TIME);
					
					else
						reply = new MessageExtraTimeCheckReply(messages.MessageExtraTimeCheckReply.ErrMsg.TIME_NOT_OVER);
		
		return reply;
	}
	
	public ErrMsg getErrorMessage()
	{
		return this.errMsg;
	}
	
	public Student getStudent()
	{
		return this.student;
	}
	
	public ExecuteTest getExecuteTest()
	{
		return this.executeTest;
	}

	public List<Choices> getChoicesList() {
		return choicesList;
	}

	public void setChoicesList(List<Choices> choicesList) {
		this.choicesList = choicesList;
	}

	public String getEndTime() {
		return endTime;
	}

	public void setEndTime(String endTime) {
		this.endTime = endTime;
	}
	


}
